using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace UwinEducation.MySqlBackup
{
    /// <summary>
    /// 使用mysqldump命令行工具执行MySQL数据库备份
    /// </summary>
    public class MySqlDumpBackup
    {
        private readonly ILogger _logger;
        private readonly string _mysqlDumpPath;
        private readonly string _host;
        private readonly int _port;
        private readonly string _username;
        private readonly string _password;
        private readonly string _database;
        private readonly string _backupPath;
        private readonly Action<int, string> _progressCallback;

        /// <summary>
        /// 初始化MySqlDump备份工具
        /// </summary>
        /// <param name="logger">日志记录器</param>
        /// <param name="mysqlDumpPath">mysqldump可执行文件路径</param>
        /// <param name="host">MySQL主机地址</param>
        /// <param name="port">MySQL端口</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="database">数据库名称</param>
        /// <param name="backupPath">备份文件保存路径</param>
        /// <param name="progressCallback">进度回调函数</param>
        public MySqlDumpBackup(
            ILogger logger,
            string mysqlDumpPath,
            string host,
            int port,
            string username,
            string password,
            string database,
            string backupPath,
            Action<int, string> progressCallback
        )
        {
            _logger = logger;
            _mysqlDumpPath = mysqlDumpPath;
            _host = host;
            _port = port;
            _username = username;
            _password = password;
            _database = database;
            _backupPath = backupPath;
            _progressCallback = progressCallback;
        }

        /// <summary>
        /// 执行数据库备份
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>备份文件名</returns>
        public async Task<string> BackupDatabaseAsync(CancellationToken cancellationToken)
        {
            try
            {
                _progressCallback(5, "准备使用mysqldump执行备份...");

                // 确保备份目录存在
                Directory.CreateDirectory(_backupPath);

                // 生成备份文件名
                string backupFileName = $"dump_{DateTime.Now:yyyyMMdd_HHmmss}.sql";
                string backupFilePath = Path.Combine(_backupPath, backupFileName);

                _progressCallback(10, "执行mysqldump命令...");

                // 创建mysqldump进程
                using (var process = new Process())
                {
                    // 准备mysqldump命令
                    process.StartInfo.FileName = _mysqlDumpPath;
                    process.StartInfo.Arguments = BuildMySqlDumpArguments(backupFilePath);
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.RedirectStandardError = true;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.CreateNoWindow = true;

                    // 输出和错误处理
                    var outputBuilder = new StringBuilder();
                    var errorBuilder = new StringBuilder();

                    process.OutputDataReceived += (sender, args) =>
                    {
                        if (!string.IsNullOrEmpty(args.Data))
                        {
                            outputBuilder.AppendLine(args.Data);
                        }
                    };

                    process.ErrorDataReceived += (sender, args) =>
                    {
                        if (!string.IsNullOrEmpty(args.Data))
                        {
                            errorBuilder.AppendLine(args.Data);
                        }
                    };

                    // 启动进程
                    _logger.LogInformation("开始执行mysqldump命令");
                    process.Start();
                    process.BeginOutputReadLine();
                    process.BeginErrorReadLine();

                    // 等待进程完成或被取消
                    int progress = 20;
                    while (!process.HasExited)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        
                        // 模拟进度更新（因为mysqldump不提供实时进度）
                        if (progress < 90)
                        {
                            progress += 5;
                            _progressCallback(progress, $"mysqldump备份进行中... {progress}%");
                        }
                        
                        await Task.Delay(1000, cancellationToken);
                    }

                    // 检查进程退出代码
                    if (process.ExitCode != 0)
                    {
                        string errorMessage = errorBuilder.ToString();
                        _logger.LogError($"mysqldump失败，退出代码: {process.ExitCode}，错误: {errorMessage}");
                        throw new Exception($"mysqldump失败，退出代码: {process.ExitCode}，错误: {errorMessage}");
                    }

                    _progressCallback(95, "mysqldump备份完成，正在验证备份文件...");

                    // 验证备份文件是否创建成功
                    if (!File.Exists(backupFilePath) || new FileInfo(backupFilePath).Length == 0)
                    {
                        throw new Exception("备份文件未创建或为空");
                    }

                    _progressCallback(100, "数据库备份成功");
                    _logger.LogInformation($"mysqldump备份成功: {backupFilePath}");

                    return backupFileName;
                }
            }
            catch (OperationCanceledException)
            {
                _logger.LogWarning("mysqldump备份操作已取消");
                throw;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "mysqldump备份失败: {Message}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// 构建mysqldump命令行参数
        /// </summary>
        /// <param name="backupFilePath">备份文件路径</param>
        /// <returns>命令行参数字符串</returns>
        private string BuildMySqlDumpArguments(string backupFilePath)
        {
            var args = new StringBuilder();

            // 添加连接参数
            args.Append($"--host={_host} ");
            args.Append($"--port={_port} ");
            args.Append($"--user={_username} ");
            
            // 添加密码（如果有）
            if (!string.IsNullOrEmpty(_password))
            {
                args.Append($"--password={_password} ");
            }
            
            // 添加其他常用选项
            args.Append("--single-transaction ");  // 保持一致性
            args.Append("--set-gtid-purged=OFF ");  // 避免GTID相关警告
            args.Append("--default-character-set=utf8mb4 ");  // 使用UTF8MB4字符集
            args.Append("--routines ");  // 包含存储过程和函数
            args.Append("--triggers ");  // 包含触发器
            args.Append("--events ");  // 包含事件
            args.Append("--add-drop-table ");  // 添加DROP TABLE语句
            args.Append("--add-drop-database ");  // 添加DROP DATABASE语句
            args.Append("--comments ");  // 包含注释
            args.Append("--complete-insert ");  // 使用完整INSERT语句
            
            // 添加数据库名称
            args.Append($"{_database} ");
            
            // 添加输出文件
            args.Append($"--result-file=\"{backupFilePath}\"");
            
            return args.ToString();
        }
    }
} 